/**
 * Highlights code
 * 
 * @copyright PORTALIER Julien
 * @license   The LGPL 2.1 License
 */

var Code = {
	Languages: {}
};

Code.Highlight = new Class(
{
	initialize: function(element)
	{
		this.element = $(element);
		
		if (!this.element || !this.element.hasAttribute('class'))
			return false;
		
		this.language = this.element.getAttribute('class');
		
		if (!Code.Languages[this.language])
			return false;
		
		this.parse();
	},
	
	parse: function()
	{
		this.rules = Code.Languages[this.language];
		var _rules = [];
		
		// parses rules
		for (var type in this.rules)
		{
			var rule = this.rules[type];
			
			// a regexp: recreate a string
			rule.exp = '(' + String(rule.exp).replace(/(^\/|\/$)/g, '') + ')';
			
			// number of sub-expressions in rule
			rule.length = (rule.exp.match(/(^|[^\\])\([^?]/g) || "").length + 1;
			
			console.log(rule.length, type, rule.exp);
			
			if (!rule.replacement)
				rule.replacement = '<span class="' + type + '">$0</span>';
			
			_rules.push('' + rule.exp + '');
		}
		
		// gets and uniforms text
		var text = this.element.innerHTML.replace(/\r/g, "\n", text);
		if (!/\n$/.test(text))
			text += "\n";
		
		// applies rules
		text = text.replace(new RegExp(_rules.join('|'), 'g'), this.replace.bind(this));
		
		// sets highlighted text
		this.element.innerHTML = text;
	},
	
	replace: function()
	{
		var j = 1;
		
		for (var type in this.rules)
		{
			var rule = this.rules[type];
			
			if (arguments[j])
			{
				var text = rule.replacement.replace(new RegExp('\\$0', 'g'), arguments[0]);
				for (i=1; i<rule.length; i++) {
					text = text.replace(new RegExp('\\$' + i, 'g'), arguments[j + i]);
				}
				return text;
			}
			else {
				j += rule.length;
			}
		}
		
		// should never happen
		return arguments[0];
	}
});

Code.Languages.javascript = {
	'comment': {
		exp: /(\/\/[^\n]*(\n|$))|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
	},
	'string': {
		exp: /('[^']*')|("[^"]*")/
	},
	'keyword': {
		exp: /\b(arguments|break|bind|catch|case|continue|default|delete|do|else|for|function|if|in|instanceof|new|return|switch|throw|try|typeof|var|void|while|with)\b/
	},
	'var': {
		exp: /\b(true|false|null|undefined)\b/,
	},
	'object': {
		exp: /\b(window|document|this|Array|Boolean|Date|Error|Function|Math|Number|Object|RegExp|String)\b/
	}
};

Code.Languages.css = {
	'comment': {
		exp: /(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
	},
	'selector': {
		exp: /[^{]*([\w-_#.,\s\n]+)[\s\n]*\{/,
		replacement: '<span class="$0">$1</span>'
	},
	'property': {
		exp: /\{[^}]*([\w-]+):/,
		replacement: '<span class="$0">$1</span>'
	}
};

// automatically highlights CODE elements' content
Window.onDomReady(function()
{
	$S('code').each(function(el) {
		new Code.Highlight(el);
	});
});
